module Enderize where

import Char
import Data.List
import Support

{- Enderize -}

type Codeline = (Int, String)
type Codelines = [Codeline]

splitCode :: String -> Codelines
splitCode = foldr aggr [] . lines
      where
        aggr line res | isEmptyLine line = res
                      | otherwise        = (length spaces, trimRight code) : res
          where
            (spaces, code) = span isSpace line

buildTree :: Codelines -> Tree String
buildTree ls = Node "" $ aux ls
  where
    aux :: Codelines -> [Tree String]
    aux [] = []
    aux [(_, code)] = [leaf code]
    aux (line:ls) | lev == lev' = leaf code : aux ls
                  | otherwise   = Node code (aux ls') : aux rest
      where
        (lev, code) = line
        lev'        = fst $ head ls
        (ls', rest) = span (lowerLevel line) ls
        
        lowerLevel :: Codeline -> Codeline -> Bool
        lowerLevel (a, _) (b, _) = a < b

showTree :: Tree String -> String
showTree (Node _ ts) = intercalate "\n" $ concat $ map aux ts
  where
    aux :: Tree String -> [String]
    aux (Node x []) = [x]
    aux (Node x ts) = (x ++ sep) : ls''
      where
        sep = if last x == ':' then "" else ":"
        (l:ls) = concat $ map aux ts
        ls' = ("{ " ++ l) : indentLines 2 ls
        (rs, r) = takeLast ls'
        ls'' = rs ++ [r ++ " }"]

enderize :: String -> String
enderize = showTree . buildTree . splitCode . unlinerize

-- Mette in una singola linea le istruzioni spezzate in più linee
-- bug: tratta i commenti come istruzioni!
unlinerize :: String -> String
unlinerize = foldl aggr "" . lines
  where
    aggr out line = out ++ line ++ if isBrokenLine line then "" else "\n"
    
    isBrokenLine :: String -> Bool
    isBrokenLine line | isEmptyLine line = False
                      | otherwise        = not $ isOk $ last line
      where
        isOk c = isAlphaNum c || 
                 isCloseParenthesis c || 
                 c `elem` "\"'" ||
                 "++" `isSuffixOf` line ||
                 "--" `isSuffixOf` line